package com.hanxiaozhang.threadbase1ndedition.no5juccommonclass;

import java.util.Random;
import java.util.concurrent.Phaser;
import java.util.concurrent.TimeUnit;

/**
 * 〈一句话功能简述〉<br>
 * 〈Phaser 移相器〉
 * <p>
 * 概念：
 * 它把多个线程协作执行的任务划分为多个阶段，编程时需要明确各个阶段的任务，
 * 每个阶段都可以有任意个参与者，线程都可以随时注册并参与到某个阶段。
 * <p>
 * 分阶段并发的问题（平时没有用到过）
 * <p>
 * 常见方法：
 * Phaser(int parties) 构造方法，parties 给定的已注册用户数。
 * register()：向移相器添加一个新的未达到的party。
 * bulkRegister(int parties)：批量向移相器添加新的未达到的party。
 * arrive()：到达该相位器，无需等待其他相位器到达
 * arriveAndDeregister()：到达此相位器并从中注销，无需等待其他相位器到达
 * arriveAndAwaitAdvance()：到达此相位器并等待其他相位器
 *
 *
 * @author hanxinghua
 * @create 2021/11/14
 * @since 1.0.0
 */
public class No4Phaser {

    private static Random r = new Random();

    private static MarriagePhaser phaser = new MarriagePhaser();


    public static void main(String[] args) {

        phaser.bulkRegister(7);

        for (int i = 0; i < 5; i++) {

            new Thread(new Person("p" + i)).start();
        }

        new Thread(new Person("新郎")).start();
        new Thread(new Person("新娘")).start();

    }


    /**
     * 婚礼移相器
     */
    static class MarriagePhaser extends Phaser {

        @Override
        protected boolean onAdvance(int phase, int registeredParties) {

            switch (phase) {
                case 0:
                    System.out.println("所有人到齐了！" + registeredParties);
                    System.out.println();
                    return false;
                case 1:
                    System.out.println("所有人吃完了！" + registeredParties);
                    System.out.println();
                    return false;
                case 2:
                    System.out.println("所有人离开了！" + registeredParties);
                    System.out.println();
                    return false;
                case 3:
                    System.out.println("婚礼结束！新郎新娘抱抱！" + registeredParties);
                    return true;
                default:
                    return true;
            }
        }

    }


    static class Person implements Runnable {

        private String name;

        public Person(String name) {
            this.name = name;
        }


        /**
         * 到达
         */
        public void arrive() {

            milliSleep(r.nextInt(1000));
            System.out.printf("%s 到达现场！\n", name);
            phaser.arriveAndAwaitAdvance();
        }


        /**
         * 吃席
         */
        public void eat() {
            milliSleep(r.nextInt(1000));
            System.out.printf("%s 吃完!\n", name);
            phaser.arriveAndAwaitAdvance();
        }


        /**
         * 离开
         */
        public void leave() {
            milliSleep(r.nextInt(1000));
            System.out.printf("%s 离开！\n", name);
            phaser.arriveAndAwaitAdvance();
        }


        /**
         * 洞房
         */
        private void hug() {
            if (name.equals("新郎") || name.equals("新娘")) {
                milliSleep(r.nextInt(1000));
                System.out.printf("%s 洞房！\n", name);
                phaser.arriveAndAwaitAdvance();
            } else {
                phaser.arriveAndDeregister();
            }
        }

        @Override
        public void run() {

            arrive();
            eat();
            leave();
            hug();
        }
    }


    static void milliSleep(int milli) {
        try {
            TimeUnit.MILLISECONDS.sleep(milli);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }


}

